//! Linux systemd journal Appender
//!
//! 将 FATAL 级别日志写入 systemd journal。
//!
//! ## 功能
//!
//! - 使用 libsystemd 的 journal API
//! - 设置 SYSLOG_IDENTIFIER 标识应用来源
//! - 同步写入确保进程崩溃前完成
//!
//! ## 示例
//!
//! ```rust,ignore
//! use log4r::appender::syslog::linux::JournaldAppender;
//! use log4r::appender::syslog::SyslogAppender;
//! use log4r::{LogEvent, Level};
//!
//! let appender = JournaldAppender::new("my_app");
//! let event = LogEvent::new(Level::Fatal, "my_app", "严重错误");
//! appender.write_syslog(&event).ok();
//! ```

use crate::error::Log4rError;
use crate::event::LogEvent;

use super::SyslogAppender;

use libsystemd::logging::{journal_send, Priority};

/// Linux systemd journal Appender
///
/// 将 FATAL 级别日志写入 systemd journal。
/// 使用 SYSLOG_IDENTIFIER 标识应用来源。
///
/// ## 线程安全
///
/// `JournaldAppender` 实现 `Send + Sync`，可以安全地在线程间共享。
/// - `identifier` 是 `String`，本身是 `Send + Sync`
/// - 没有内部可变状态
///
/// ## 示例
///
/// ```rust,ignore
/// use log4r::appender::syslog::linux::JournaldAppender;
/// use log4r::appender::syslog::SyslogAppender;
///
/// let appender = JournaldAppender::new("my_app");
/// assert_eq!(appender.name(), "JournaldAppender");
/// ```
pub struct JournaldAppender {
    /// 日志标识符（app_name）
    identifier: String,
}

impl JournaldAppender {
    /// 创建新的 systemd journal Appender
    ///
    /// # Arguments
    ///
    /// * `app_name` - 应用名称，用作 SYSLOG_IDENTIFIER
    ///
    /// # Returns
    ///
    /// 返回新的 `JournaldAppender` 实例
    ///
    /// # 示例
    ///
    /// ```rust,ignore
    /// use log4r::appender::syslog::linux::JournaldAppender;
    ///
    /// let appender = JournaldAppender::new("my_app");
    /// ```
    pub fn new(app_name: &str) -> Self {
        Self {
            identifier: app_name.to_string(),
        }
    }

    /// 获取日志标识符
    ///
    /// # Returns
    ///
    /// 返回日志标识符的引用
    pub fn identifier(&self) -> &str {
        &self.identifier
    }

    /// 格式化日志消息
    ///
    /// 格式: `{timestamp} [{level}] {target}: {message}`
    ///
    /// # Arguments
    ///
    /// * `event` - 日志事件
    ///
    /// # Returns
    ///
    /// 格式化后的消息字符串
    fn format_message(&self, event: &LogEvent) -> String {
        // 使用 RFC3339 格式化时间戳，失败时使用默认格式
        let timestamp = event
            .timestamp
            .format(&time::format_description::well_known::Rfc3339)
            .unwrap_or_else(|_| event.timestamp.to_string());

        format!(
            "{} [{}] {}: {}",
            timestamp, event.level, event.target, event.message
        )
    }
}

impl SyslogAppender for JournaldAppender {
    /// 同步写入 systemd journal
    ///
    /// # Arguments
    ///
    /// * `event` - 要写入的日志事件
    ///
    /// # Returns
    ///
    /// * `Ok(())` - 写入成功
    /// * `Err(Log4rError::AppenderError)` - 写入失败
    ///
    /// # 日志级别映射
    ///
    /// FATAL 级别映射到 LOG_CRIT (Priority::Critical, 值为 2)
    fn write_syslog(&self, event: &LogEvent) -> Result<(), Log4rError> {
        // 验证 identifier 非空
        if self.identifier.is_empty() {
            return Err(Log4rError::AppenderError {
                name: "JournaldAppender".to_string(),
                cause: "app_name 不能为空".to_string(),
            });
        }

        let message = self.format_message(event);

        // 构建 journal 字段
        // SYSLOG_IDENTIFIER: 应用标识符
        // PRIORITY: 日志优先级（2 = LOG_CRIT）
        // LOG4R_LEVEL: log4r 日志级别
        // LOG4R_TARGET: 日志目标模块
        let level_str = event.level.to_string();
        let fields: Vec<(&str, &str)> = vec![
            ("SYSLOG_IDENTIFIER", &self.identifier),
            ("LOG4R_LEVEL", &level_str),
            ("LOG4R_TARGET", event.target.as_ref()),
        ];

        // 使用 Priority::Critical (LOG_CRIT = 2) 写入 journal
        journal_send(Priority::Critical, &message, fields.into_iter()).map_err(|e| {
            Log4rError::AppenderError {
                name: "JournaldAppender".to_string(),
                cause: format!("journal_send 失败: {}", e),
            }
        })
    }

    fn name(&self) -> &'static str {
        "JournaldAppender"
    }
}

// JournaldAppender 是 Send + Sync 安全的
// - identifier 是 String，本身是 Send + Sync
// - 没有内部可变状态
// - libsystemd journal_send 是线程安全的
unsafe impl Send for JournaldAppender {}
unsafe impl Sync for JournaldAppender {}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::level::Level;

    // UT-8.2-001: 测试 JournaldAppender::new() 创建 (AC: 8.2.2)
    #[test]
    fn test_journald_appender_new() {
        // GIVEN: 应用名称
        let app_name = "test_app";

        // WHEN: 创建 JournaldAppender
        let appender = JournaldAppender::new(app_name);

        // THEN: identifier 应正确设置
        assert_eq!(appender.identifier(), "test_app");
    }

    // UT-8.2-002: 测试消息格式化包含所有字段 (AC: 8.2.4)
    #[test]
    fn test_format_message_contains_all_fields() {
        // GIVEN: JournaldAppender 和 LogEvent
        let appender = JournaldAppender::new("my_app");
        let event = LogEvent::new(Level::Fatal, "my_app::module", "严重错误消息");

        // WHEN: 格式化消息
        let message = appender.format_message(&event);

        // THEN: 消息应包含所有字段
        // 格式: {timestamp} [{level}] {target}: {message}
        assert!(message.contains("[FATAL]"), "应包含级别: {}", message);
        assert!(
            message.contains("my_app::module"),
            "应包含 target: {}",
            message
        );
        assert!(message.contains("严重错误消息"), "应包含消息: {}", message);
        // 时间戳应为 RFC3339 格式（包含 T 和时区）
        assert!(
            message.contains("T") || message.contains("-"),
            "应包含时间戳: {}",
            message
        );
    }

    // UT-8.2-003: 测试日志级别为 LOG_CRIT (AC: 8.2.3)
    #[test]
    fn test_priority_is_critical() {
        // GIVEN: Priority::Critical
        // WHEN: 检查值
        // THEN: Priority::Critical 对应 LOG_CRIT (2)
        // libsystemd 的 Priority::Critical 内部值为 2
        assert_eq!(Priority::Critical as u8, 2);
    }

    // UT-8.2-004: 测试 SyslogAppender trait 实现 (AC: 8.2.1)
    #[test]
    fn test_syslog_appender_trait_implementation() {
        // GIVEN: JournaldAppender
        let appender = JournaldAppender::new("test_app");

        // WHEN: 调用 trait 方法
        let name = appender.name();

        // THEN: 应返回正确的名称
        assert_eq!(name, "JournaldAppender");
    }

    // UT-8.2-005: 测试 JournaldAppender 是 Send + Sync
    #[test]
    fn test_journald_appender_is_send_sync() {
        // GIVEN: JournaldAppender
        // WHEN: 检查 Send + Sync
        // THEN: 编译通过即验证成功
        fn assert_send<T: Send>() {}
        fn assert_sync<T: Sync>() {}

        assert_send::<JournaldAppender>();
        assert_sync::<JournaldAppender>();
    }

    // UT-8.2-006: 测试 SYSLOG_IDENTIFIER 字段正确设置 (AC: 8.2.2)
    #[test]
    fn test_syslog_identifier_field() {
        // GIVEN: 应用名称
        let app_name = "log4r_test_app";
        let appender = JournaldAppender::new(app_name);

        // THEN: identifier 应与 app_name 一致
        assert_eq!(appender.identifier(), app_name);
    }

    // UT-8.2-007: 测试空应用名称创建成功但写入失败
    #[test]
    fn test_empty_app_name() {
        // GIVEN: 空应用名称
        let appender = JournaldAppender::new("");

        // THEN: 创建应成功
        assert_eq!(appender.identifier(), "");
    }

    // UT-8.2-008: 测试空应用名称写入时返回错误
    #[test]
    fn test_empty_app_name_write_returns_error() {
        // GIVEN: 空应用名称的 Appender
        let appender = JournaldAppender::new("");
        let event = LogEvent::new(Level::Fatal, "test", "测试消息");

        // WHEN: 尝试写入
        let result = appender.write_syslog(&event);

        // THEN: 应返回错误
        assert!(result.is_err());
        if let Err(err) = result {
            assert!(err.to_string().contains("app_name"));
        }
    }

    // UT-8.2-009: 测试 Unicode 应用名称
    #[test]
    fn test_unicode_app_name() {
        // GIVEN: Unicode 应用名称
        let appender = JournaldAppender::new("日志应用");

        // THEN: 应正确保存
        assert_eq!(appender.identifier(), "日志应用");
    }

    // UT-8.2-010: 测试消息格式化 Unicode 内容
    #[test]
    fn test_format_message_unicode() {
        // GIVEN: Unicode 内容的 LogEvent
        let appender = JournaldAppender::new("测试");
        let event = LogEvent::new(Level::Fatal, "日志::模块", "错误消息 🚀");

        // WHEN: 格式化消息
        let message = appender.format_message(&event);

        // THEN: Unicode 应正确保存
        assert!(message.contains("日志::模块"));
        assert!(message.contains("🚀"));
    }

    // 注意：实际的 systemd journal 写入测试需要在 Linux 系统上运行
    // 并且需要 systemd 环境，因此标记为 #[ignore]
    #[test]
    #[ignore]
    fn test_write_syslog_integration() {
        // GIVEN: JournaldAppender 和 FATAL 事件
        let appender = JournaldAppender::new("log4r_test");
        let event = LogEvent::new(Level::Fatal, "log4r::test", "集成测试消息");

        // WHEN: 写入系统日志
        let result = appender.write_syslog(&event);

        // THEN: 应成功（在 Linux 上）
        // 注意：可能因环境问题失败
        println!("写入结果: {:?}", result);
    }
}
